package com.joinway.framework.extension.net.http;

import java.io.IOException;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import org.apache.http.Consts;
import org.apache.http.client.ClientProtocolException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.joinway.framework.extension.net.http.bean.HttpMethod;
import com.joinway.framework.extension.net.http.bean.SignParam;
import com.joinway.framework.extension.net.http.type.ParamOrder;

public class SignedParamHttpClient {

	private final static Logger log = LoggerFactory.getLogger(SignedParamHttpClient.class);
	
//	protected SignedParamHttpClientConfig config = new SignedParamHttpClientConfig();
	
	public SignedParamHttpClient(){}
	
	public String request(String url, Map<String, String> params, SignBuilder builder) throws ClientProtocolException, IOException{
		return request(url, params, ParamOrder.None, Consts.UTF_8.toString(), HttpMethod.Post, String.class, builder);
	}
	
	public<O> O request(String url, Map<String, String> params, Class<O> type, SignBuilder builder) throws ClientProtocolException, IOException{
		return request(url, params, ParamOrder.None, Consts.UTF_8.toString(), HttpMethod.Post, type, builder);
	}
	
	public<O> O request(String url, Map<String, String> params, HttpMethod method, Class<O> type, SignBuilder builder) throws ClientProtocolException, IOException{
		return request(url, params, ParamOrder.None, Consts.UTF_8.toString(), method, type, builder);
	}

	public<O> O request(String url, Map<String, String> params, ParamOrder order, HttpMethod method, Class<O> type, SignBuilder builder) throws ClientProtocolException, IOException{
		return request(url, params, order, Consts.UTF_8.toString(), method, type, builder);
	}
	
	public<O> O request(String url, Map<String, String> params, ParamOrder order, String encode, HttpMethod method, Class<O> type, SignBuilder builder) throws ClientProtocolException, IOException{
		Map<String, String> inputs = null;
		
		if(params == null || params.size() == 0){
			return null;
		}
		
		if(order == ParamOrder.Asc){
			inputs = new TreeMap<>(new Comparator<String>() {
				@Override
				public int compare(String key1, String key2) {
					return key1.compareTo(key2);
				}
			});
		}else if(order == ParamOrder.Desc){
			inputs = new TreeMap<>(new Comparator<String>() {
				@Override
				public int compare(String key1, String key2) {
					return key2.compareTo(key1);
				}
			});
		}else{
			inputs = new LinkedHashMap<>();
		}
		
		Set<Entry<String, String>> entries = params.entrySet();
		for(Entry<String, String> entry : entries){
			String key = entry.getKey();
			String value = entry.getValue();
			if(value != null && value.trim().length() > 0){
				inputs.put(key, value);
			}else{
				log.warn("ignored empty param {}", key);
			}
		}
		
		if(builder != null){
			SignParam sp = builder.build(inputs);
			inputs.put(sp.getName(), sp.getValue());
		}
		
		log.debug("destination url {}", url);
		log.debug("{} signed params -> {}", method, inputs);
		
		RestHttpClient client = new RestHttpClient();
		O output = null;
		
		if(HttpMethod.Put == method){
			output = client.put(url, inputs, encode, type);
		}else{
			output = client.post(url, inputs, encode, type);
		}
		
		log.debug("sign http client got output -> {}", output);
		
		return output;
	}
}
